
//#include "lexer.hpp"
#include <map>
#include <cstdlib>
#include <string>
#include <vector>

#include "semantic.hpp"

//using namespace std;

Semantic::Semantic()
{
	cubeinit();
	state = true;
}

void Semantic::cubeinit()
{
	// Set up sizes. (HEIGHT x WIDTH x DEPTH) -- for vector version
	/*cube.resize(6); //# of operator tables
	for (int i = 0; i < 6; i++)
	{
		cube[i].resize(7); //height


		for (int j = 0; j < 4; j++)
			cube[i][j].resize(7); //width of tables with 2 operands
		for(int k = 4; k<6; k++)
			cube[i][k].resize(2); //width of tables with one operand
	}*/

	//cube[operator#][height][width]
	//cube[operator#][0][0] -- upper left corner of operator table

	//initializing borders and setting everything else to "error"
	for(int i = 0; i < 6; i++)
	{
		for(int j = 0; j < 7; j++)
		{
			for(int k = 0; k < 7; k++)
			{
					if(j == 0)
					{
						switch(k){
						case 1:
							cube[i][j][k] = "integer";
							break;
						case 2:
							cube[i][j][k] = "float";
							break;
						case 3:
							cube[i][j][k] = "char";
							break;
						case 4:
							cube[i][j][k] = "string";
							break;
						case 5:
							cube[i][j][k] = "boolean";
							break;
						case 6:
							cube[i][j][k] = "void";
							break;
						default:
							cube[i][j][k] = "error";
							break;
						}
					}
					else
					{
						if(k == 0)
						{
							switch(j){
							case 1:
								cube[i][j][k] = "integer";
								break;
							case 2:
								cube[i][j][k] = "float";
								break;
							case 3:
								cube[i][j][k] = "char";
								break;
							case 4:
								cube[i][j][k] = "string";
								break;
							case 5:
								cube[i][j][k] = "boolean";
								break;
							case 6:
								cube[i][j][k] = "void";
								break;
							default:
								cube[i][j][k] = "error";
								break;
							}
						}
						else
							cube[i][j][k] = "error";
					}
			}
		}
	}

	//setting entries that aren't "error"
	//+
	cube[0][0][0] = "plus";
	cube[0][1][1] = "integer";
	cube[0][2][1] = "float";
	cube[0][2][2] = "float";
	cube[0][1][2] = "float";
	for(int i = 1; i < 6; i++)
	{
		cube[0][4][i] = "string";
		cube[0][i][4] = "string";
	}

	//-,*,/
	cube[1][0][0] = "submultdiv";
	cube[1][1][1] = "integer";
	cube[1][2][1] = "float";
	cube[1][2][2] = "float";
	cube[1][1][2] = "float";

	//- (unary)
	cube[2][0][0] = "neg";
	cube[2][1][1] = "integer";
	cube[2][2][1] = "float";

	//<,>
	cube[3][0][0] = "ltgt";
	cube[3][1][1] = "boolean";
	cube[3][2][1] = "boolean";
	cube[3][2][2] = "boolean";
	cube[3][1][2] = "boolean";

	//!
	cube[4][0][0] = "no";
	cube[4][5][1] = "boolean";

	//&,|
	cube[5][0][0] = "andor";
	cube[5][5][5] = "boolean";
}

void Semantic::push(string type)
{
	stack.push_back(type);
}

string Semantic::pop()
{
	string ret = stack[stack.size() - 1];
	stack.pop_back();
	return ret;
}

int Semantic::lookup(string type)
{
	if(type.compare("integer")==0)
	{
		return 1;
	}
	else
	{
		if(type.compare("float")==0)
		{
			return 2;
		}
		else
		{
			if(type.compare("char")==0)
			{
				return 3;
			}
			else
			{
				if(type.compare("string")==0)
				{
					return 4;
				}
				else
				{
					if(type.compare("boolean")==0)
					{
						return 5;
					}
					else
					{
						return 6;
					}
				}
			}
		}
	}
}

/*bool isTypeMatching(string type)
{

}*/

/*bool Semantic::varUnicity()
{
	//if(
}*/

/*bool Semantic::checkStack()
{
	string type;
	if(stack.size() > 1)
	{
		type = cube[
		if(currentToken().word == ";")
		{

		}
	}

}*/

/*int Semantic::convertToIndex(std::string type)
{
	int typenum;

	//if(type.compare("
}*/
std::string Semantic::isEmpty() {
	if (stack.size() == 0) {
		return "error";
	}
	return pop();
}

bool Semantic::isBool() {
	std::string type = stack[stack.size()-1];
	if (type == "boolean") {
		pop();
		return true;
	}
	pop();
	return false;
}


std::string Semantic::calcTypeBin(std::string op)
{
	int opnum;
	if(op.compare("+") == 0)
	{
		opnum = 0;
	}
	else
	{
		if(op.compare("-") == 0 || op.compare("*") == 0 || op.compare("/") == 0)
		{
			opnum = 1;
		}
		else
		{
			if(op.compare(">") == 0 || op.compare("<") == 0)
			{
				opnum = 3;
			}
			else
			{
				opnum = 5;
			}
		}
	}


	std::string type = cube[opnum][lookup(stack[stack.size()-2])][lookup(stack[stack.size()-1])];
	pop();
	pop();
	if(type.compare("error") != 0)
	{
		push(type);
	}
	return type;
}

std::string Semantic::calcTypeUn(std::string op)
{
	int opnum;
	if(op.compare("-") == 0)
		opnum = 2;
	else
		opnum = 4;

	std::string type = cube[opnum][lookup(stack[stack.size()-1])][1];
	pop();
	if(type.compare("error") != 0)
	{
		push(type);
	}
	return type;
}
